package com.cl.ks.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cl.ks.entity.*;
import com.cl.ks.enums.TargetType;
import com.cl.ks.repository.*;
import com.cl.ks.utils.DbUtil;
import com.cl.ks.utils.QueryDslUtil;
import com.jandar.pile.common.util.IParamBundle;
import com.jandar.pile.common.util.JwtUtil;
import com.jandar.pile.common.util.PageBundle;
import com.jandar.pile.common.util.ParamBundle;
import com.cl.pile.rule.filter.IFilterOperation;
import com.cl.pile.rule.func.IFunc;
import com.cl.pile.rule.process.RuleMatcher;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.cl.ks.constant.QTableConstant.*;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

/**
 * @author chenyitao
 * @date 2021/4/20
 */
@Service
@Log
public class KsRuleServiceOld {
    private final KsFilterRepository ksFilterRepository;
    private final KsDataFieldRepository ksDataFieldRepository;

    private final RuleMatcher ruleMatcher;
    private final DbUtil dbUtil;
    private final FilterService filterService;
    private final JwtUtil<Long, Long> jwtUtil;

    private final KsRuleRepository ksRuleRepository;

    private final RlRuleTableRepository rlRuleTableRepository;

    private final KsFilterLogRepository ksFilterLogRepository;

    private final SysSourceMappingTableFieldService sysSourceMappingTableFieldService;
    private final SysSourceMappingTableService sysSourceMappingTableService;
    private final SysSourceMappingTableRepository sysSourceMappingTableRepository;

    private final KsFilterStatisticsRepository ksFilterStatisticsRepository;

    private final KsClassFieldRepository ksClassFieldRepository;


    private final JPAQueryFactory queryFactory;

    private final KsDataTypeRepository ksDataTypeRepository;

    private final KsRuleService ksRuleService;
    private final RlRuleFieldService rlRuleFieldService;
    private final KsFlowLikeService ksFlowLikeService;
    private final KsFlowCommentService ksFlowCommentService;


    public KsRuleServiceOld(RuleMatcher ruleMatcher, DbUtil dbUtil, FilterService filterService, JwtUtil<Long, Long> jwtUtil, KsRuleRepository ksRuleRepository, RlRuleTableRepository rlRuleTableRepository, KsFilterLogRepository ksFilterLogRepository, SysSourceMappingTableFieldRepository sysSourceMappingTableFieldService, SysSourceMappingTableFieldService sysSourceMappingTableFieldService1, SysSourceMappingTableService sysSourceMappingTableService, SysSourceMappingTableRepository sysSourceMappingTableRepository, KsFilterStatisticsRepository ksFilterStatisticsRepository, KsClassFieldRepository ksClassFieldRepository, JPAQueryFactory queryFactory, KsDataTypeRepository ksDataTypeRepository, RlRuleFieldService rlRuleFieldService,
                            KsDataFieldRepository ksDataFieldRepository,
                            KsFilterRepository ksFilterRepository, KsRuleService ksRuleService, KsFlowLikeService ksFlowLikeService, KsFlowCommentService ksFlowCommentService) {
        this.ruleMatcher = ruleMatcher;
        this.dbUtil = dbUtil;
        this.filterService = filterService;
        this.jwtUtil = jwtUtil;
        this.ksRuleRepository = ksRuleRepository;
        this.rlRuleTableRepository = rlRuleTableRepository;
        this.ksFilterLogRepository = ksFilterLogRepository;
        this.sysSourceMappingTableFieldService = sysSourceMappingTableFieldService1;
        this.sysSourceMappingTableService = sysSourceMappingTableService;
        this.sysSourceMappingTableRepository = sysSourceMappingTableRepository;
        this.ksFilterStatisticsRepository = ksFilterStatisticsRepository;
        this.ksClassFieldRepository = ksClassFieldRepository;
        this.queryFactory = queryFactory;
        this.ksDataTypeRepository = ksDataTypeRepository;
        this.rlRuleFieldService = rlRuleFieldService;
        this.ksRuleService = ksRuleService;
        this.ksFlowLikeService = ksFlowLikeService;
        this.ksFlowCommentService = ksFlowCommentService;
        this.initClassField();
        this.ksDataFieldRepository = ksDataFieldRepository;
        this.ksFilterRepository = ksFilterRepository;
    }


    public List<String> getKsRuleFields(String ruleExpression) {
        List<String> res = new ArrayList<>();
        String regexPattern = "\"field\": \"(.[^\"]+)\"";
        Pattern pattern = Pattern.compile(regexPattern);
        Matcher matcher = pattern.matcher(ruleExpression);
        while (matcher.find()) {
            res.add(matcher.group(1));
        }
        return res;
    }

    public List<String> getKsRuleFields(Integer ruleId) {
        List<String> res = new ArrayList<>();
        String ruleExpression = queryFactory.select(qKsRule.ruleExpressionJson).from(qKsRule).where(qKsRule.id.eq(ruleId)).fetchFirst();
        String regexPattern = "\"field\": \"(.[^\"]+)\"";
        Pattern pattern = Pattern.compile(regexPattern);
        Matcher matcher = pattern.matcher(ruleExpression);
        while (matcher.find()) {
            res.add(matcher.group(1));
        }
        return res;
    }

    public JSONArray exportKsFilters(List<Integer> ids) {
        List<KsFilter> ksFilters = ksFilterRepository.findAllById(ids);
        ksFilters.forEach(ksFilter -> {
            FilterService.FilterBundle filterBundle = JSONObject.parseObject(ksFilter.getFilterBundle(), FilterService.FilterBundle.class);
            filterBundle.getFilterParams().forEach(filterParam -> {
                Integer ksRuleId = filterParam.getKsRuleId();
                Optional<KsRule> ksRuleOptional = ksRuleRepository.findById(ksRuleId);
                if (!ksRuleOptional.isPresent()) {
                    return;
                }
                KsRule ksRule = ksRuleOptional.get();
                filterParam.setKsRule(ksRule);
            });
            ksFilter.setFilterBundle(JSONObject.toJSONString(filterBundle));
        });
        return JSONArray.parseArray(JSONObject.toJSONString(ksFilters));
    }

    public List<KsFilter> importKsFilters(String ksFiltersJson) {
        List<KsFilter> ksFilters = JSONObject.parseArray(ksFiltersJson, KsFilter.class);
        ksFilters.forEach(ksFilter -> {
            ksFilter.setId(null);
            FilterService.FilterBundle filterBundle = JSONObject.parseObject(ksFilter.getFilterBundle(), FilterService.FilterBundle.class);
            filterBundle.getFilterParams().forEach(filterParam -> {
                KsRule ksRule = importKsRule(filterParam.getKsRule());
                filterParam.setKsRule(null);
                filterParam.setKsRuleId(ksRule.getId());
            });
            ksFilter.setFilterBundle(JSONObject.toJSONString(filterBundle));
        });
        return ksFilterRepository.saveAll(ksFilters);
    }


    public JSONArray exportKsRules(List<Integer> ids) {
        List<KsRule> ksRules = ksRuleRepository.findAllById(ids);
        return JSONArray.parseArray(JSONObject.toJSONString(ksRules));
    }

    public KsRule importKsRule(KsRule ksRule) {
        ksRule.setId(null);
        KsRule newKsRule = ksRuleRepository.save(ksRule);
        Set<RlRuleTable> newRlRuleTables = new HashSet<>();
        for (RlRuleTable rlRuleTable : newKsRule.getRlRuleTableList()) {
            rlRuleTable.setId(null);
            rlRuleTable.setRuleId(newKsRule.getId());
            RlRuleTable newRlRuleTable = rlRuleTableRepository.save(rlRuleTable);
            newRlRuleTables.add(newRlRuleTable);
        }
        newKsRule.setRlRuleTableList(newRlRuleTables);
        return newKsRule;

    }

    public List<KsRule> importKsRules(List<KsRule> ksRules) {
        List<KsRule> newKsRules = new ArrayList<>();
        ksRules.forEach(ksRule -> {
            newKsRules.add(importKsRule(ksRule));
        });
        return newKsRules;
    }

    public List<KsRule> importKsRules(String ksRulesJson) {
        List<KsRule> newKsRules = new ArrayList<>();
        List<KsRule> ksRules = JSONObject.parseArray(ksRulesJson, KsRule.class);
        ksRules.forEach(ksRule -> {
            newKsRules.add(importKsRule(ksRule));
        });
        return newKsRules;
    }


    public ResponseEntity<Object> getDataSourceTemplate(Integer ruleId) {
        return ResponseEntity.ok().body(getDataSourceTemplateMap(ruleId));
    }

    public ResponseEntity<Object> getDataSourceTemplateExcel(Integer ruleId, HttpServletResponse response) {


        Map<String, Object> dataSourceTemplateMap = getDataSourceTemplateMap(ruleId);

        ExcelWriter writer = null;

        for (Map.Entry<String, Object> entry : dataSourceTemplateMap.entrySet()) {
            String key = entry.getKey();
            List<String> value = (List<String>) entry.getValue();
            if (writer == null) {
                writer = new ExcelWriter(true, key);
            }
            writer.setSheet(key);
            List<List<String>> rows = CollUtil.newArrayList(Collections.singleton(value));
            writer.write(rows, true);

        }
        String fileName = "rule" + ruleId + "template.xlsx";
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        Objects.requireNonNull(writer).flush(out, true);
        writer.close();
        IoUtil.close(out);

        return ResponseEntity.ok().body("");
    }


    public Map<String, Object> getDataSourceTemplateMap(Integer ruleId) {
        List<String> fieldCodeList = queryFactory.select(qRlRuleField.dataFieldCode).from(qRlRuleField).where(qRlRuleField.ruleId.eq(ruleId)).fetch();
        Expression[] fields = {qKsDataField.dataTypeCode, qKsDataField.dataTypeCode.count().as("count")};
        List<Map<String, Object>> list = QueryDslUtil.tupleListToMapList(queryFactory.select(fields).from(qKsDataField).where(qKsDataField.code.in(fieldCodeList)).groupBy(qKsDataField.dataTypeCode).fetch(), fields);
        List<String> dataTypeCodeList = list.stream().map(item -> {
            Long count = (Long) item.get("count");
            String dataTypeCode = (String) item.get("dataTypeCode");
            Long totalCount = queryFactory.select(qKsDataField.dataTypeCode.count()).from(qKsDataField).where(qKsDataField.dataTypeCode.eq(dataTypeCode)).fetchOne();
            return Objects.equals(totalCount, count) ? dataTypeCode : null;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        List<KsDataField> ksDataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.in(dataTypeCodeList)).fetch();
        Map<String, String> codeNameMap = queryFactory.selectFrom(qKsDataType).where(qKsDataType.code.in(dataTypeCodeList)).fetch().stream().collect(Collectors.toMap(KsDataType::getCode, KsDataType::getName));
        Map<String, Object> res = new TreeMap<>();
        ksDataFieldList.forEach(ksDataField -> {
            String name = codeNameMap.get(ksDataField.getDataTypeCode());
            if (name == null) {
                return;
            }
            if (!res.containsKey(name)) {
                res.put(name, new ArrayList<>());
            }
            ((List<String>) (res.get(name))).add(ksDataField.getFieldName());
        });
        return res;
    }

    public ResponseEntity<Object> listAvailableRuleByDataTypeCode(String dataTypeCode) {
        List<KsDataField> ksDataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.eq(dataTypeCode)).fetch();
        List<String> fieldCodeList = ksDataFieldList.stream().map(KsDataField::getCode).collect(Collectors.toList());
        List<KsRule> res = listRuleByFieldCodeList(fieldCodeList);
        return ResponseEntity.ok().body(res);
    }

    public List<KsRule> listAvailableRuleContainsDataTypeCode(String dataTypeCode) {
        List<KsDataField> ksDataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.contains(dataTypeCode)).fetch();
        List<String> fieldCodeList = ksDataFieldList.stream().map(KsDataField::getCode).collect(Collectors.toList());
        List<KsRule> res = listRuleByFieldCodeList(fieldCodeList);
        return res;
    }

    public List<KsRule> listAvailableRuleContainsDataTypeName(String dataTypeName) {
        List<String> fieldCodeList = queryFactory.select(qKsDataField.code).from(qKsDataField).rightJoin(qKsDataType).on(qKsDataField.dataTypeCode.eq(qKsDataType.code)).where(qKsDataType.name.contains(dataTypeName)).fetch();
        List<KsRule> res = listRuleByFieldCodeList(fieldCodeList);
        return res;
    }

    //    public Integer getRuleCount(String dataTypeCodes,String auth) {
//        List<KsDataField> ksDataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.in(dataTypeCodes)).fetch();
//        List<String> fieldCodeList = ksDataFieldList.stream().map(KsDataField::getCode).collect(Collectors.toList());
//        Map<String,Object> ksRuleParams = new HashMap<>();
//        ksRuleParams.put("")
//        KsRule ksRuleParam = new KsRule();
//        ksRuleParam.setParams();
//        ksRuleService.findAll(ksRuleParam,auth)
//    }
    public List<KsRule> listAvailableRuleByDataTypeCodes(List<String> dataTypeCodes, List<String> names, String auth) {
        try {
            List<KsDataField> ksDataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.in(dataTypeCodes)).fetch();
            List<String> fieldCodeList = ksDataFieldList.stream().map(KsDataField::getCode).collect(Collectors.toList());
            return listRuleByFieldCodeList(dataTypeCodes, fieldCodeList, names, auth);
        } catch (Exception e) {
            log.info(e.getMessage());
            return new ArrayList<>();
        }

    }

    public List<KsRule> listAvailableRuleByDataTypeCode(String dataTypeCode, List<String> names, String auth) {
        try {
            List<KsDataField> ksDataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.eq(dataTypeCode)).fetch();
            List<String> fieldCodeList = ksDataFieldList.stream().map(KsDataField::getCode).collect(Collectors.toList());
            return listRuleByFieldCodeList(new ArrayList<>(Collections.singletonList(dataTypeCode)), fieldCodeList, names, auth);
        } catch (Exception e) {
            log.info(e.getMessage());
            return new ArrayList<>();
        }

    }

    public List<KsRule> listRuleByFieldCodeList(List<String> dataTypeCodes, List<String> fieldCodeList, List<String> names, String auth) {
        String userId = String.valueOf(jwtUtil.getUserId(auth));
        String roleId = String.valueOf(jwtUtil.getRoleId(auth));
        String depId = String.valueOf(jwtUtil.getDepId(auth));
        BooleanExpression booleanExpression = QueryDslUtil.generatePowerExpression(qKsRule, qKsRule.power, userId, roleId, depId).and(qRlRuleField.dataFieldCode.in(fieldCodeList));

        if (names != null && !names.isEmpty()) {
            BooleanExpression booleanNameExpression = qKsRule.isNull().and(qKsRule.isNotNull());
            for (String name : names) {
                booleanNameExpression = booleanNameExpression.or(qKsRule.ruleName.contains(name));
            }
            booleanExpression = booleanExpression.and(booleanNameExpression);
        }

        Expression[] fields = {qKsRule.id, qRlRuleField.dataFieldCode.count().as("count")};
        List<Map<String, Object>> rules = QueryDslUtil.tupleListToMapList(queryFactory.select(fields).from(qRlRuleField).leftJoin(qKsRule).on(qKsRule.id.eq(qRlRuleField.ruleId)).where(booleanExpression.and(qKsRule.isNotNull().and(qRlRuleField.dataTypeCode.in(dataTypeCodes)))).groupBy(qRlRuleField.ruleId).fetch(), fields);
        List<KsRule> res = rules.stream().map(rule -> {
            Long count = (Long) rule.get("count");
            Integer ruleId = (Integer) rule.get("id");
            Long totalCount = queryFactory.select(qRlRuleField.dataFieldCode.count()).from(qRlRuleField).where(qRlRuleField.ruleId.eq(ruleId).and(qRlRuleField.dataTypeCode.in(dataTypeCodes))).fetchOne();
            return Objects.equals(totalCount, count) ? ruleId : null;
        }).filter(Objects::nonNull).map(ruleId -> ksRuleRepository.findById(ruleId).get()).collect(Collectors.toList());
        return res;
    }

    public ResponseEntity<Object> listAvailableRuleBySourceTableId(Integer sourceTableId) {
        SysSourceMappingTable sysSourceMappingTable = sysSourceMappingTableRepository.findById(sourceTableId).get();
        SysSourceMappingTableField fieldParam = new SysSourceMappingTableField();
        fieldParam.setTableName(sysSourceMappingTable.getTableName());
        fieldParam.setDbCode(sysSourceMappingTable.getDbCode());
        List<SysSourceMappingTableField> fieldList = sysSourceMappingTableFieldService.findAll(fieldParam);
        List<String> fieldCodeList = fieldList.stream().map(SysSourceMappingTableField::getKsDataFieldCode).collect(Collectors.toList());
        List<KsRule> res = listRuleByFieldCodeList(fieldCodeList);
        return ResponseEntity.ok().body(res);
    }

    public List<KsRule> listRuleByFieldCodeList(List<String> fieldCodeList) {
        Expression[] fields = {qRlRuleField.ruleId, qRlRuleField.dataFieldCode.count().as("count")};
        List<Map<String, Object>> rules = QueryDslUtil.tupleListToMapList(queryFactory.select(fields).from(qRlRuleField).leftJoin(qKsRule).on(qKsRule.id.eq(qRlRuleField.ruleId)).where(qRlRuleField.dataFieldCode.in(fieldCodeList)).groupBy(qRlRuleField.ruleId).fetch(), fields);
        List<KsRule> res = rules.stream().map(rule -> {
            Long count = (Long) rule.get("count");
            Integer ruleId = (Integer) rule.get("ruleId");
            Long totalCount = queryFactory.select(qRlRuleField.dataFieldCode.count()).from(qRlRuleField).where(qRlRuleField.ruleId.eq(ruleId)).fetchOne();
            return Objects.equals(totalCount, count) ? ruleId : null;
        }).filter(Objects::nonNull).map(ruleId -> ksRuleRepository.findById(ruleId)).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
        return res;
    }

    public ResponseEntity<Object> getFields(String tableName) {
        return ResponseEntity.ok().body(ksRuleRepository.getFields(tableName));
    }


    public ResponseEntity<Object> getOps() {
        List<JSONObject> ops = new ArrayList<>();
        for (Map.Entry<String, IFilterOperation> entry : ruleMatcher.getFilterOperationMap().entrySet()) {
            JSONObject item = new JSONObject();
            item.put("name", entry.getValue().filterName());
            item.put("op", entry.getKey());
            ops.add(item);
        }
        return ResponseEntity.ok().body(ops);
    }

    //todo 映射表新增失败
    public ResponseEntity<Object> addKsRule(String auth, KsRuleParam ksRuleParam) {


        String systemCode = jwtUtil.getSystemCode(auth);

        KsRule ksRule = new KsRule();
        ksRule.setRuleName(ksRuleParam.getRuleName());
        ksRule.setRuleExpressionJson(ksRuleParam.getRule().toJSONString());
        ksRule.setPower(ksRuleParam.getPower() + ",j_1");
        ksRule.setUserIds("," + ksRuleParam.getUserId() + ",");
        ksRule.setRoleIds(",1," + ksRuleParam.getRoleId() + ",");
        ksRule.setRuleType(ksRuleParam.getRuleType());
        ksRule.setIsForward(ksRuleParam.isForward);
        ksRule.setShowFields(ksRuleParam.getShowFields());
        ksRule.setSystemCode(systemCode);
        ksRule.setDescription(ksRuleParam.getDescription());
        if (StringUtils.isNotBlank(ksRuleParam.getResultPower())) {
            ksRule.setResultPower(ksRuleParam.getResultPower());
        } else {
            ksRule.setResultPower(ksRuleParam.getResultPower() + ",j_1");
        }
        try {
            ksRuleRepository.save(ksRule);
            createRlRuleTable(ksRuleParam.getRlRuleTableList(), ksRule.getId());
            createRlRuleField(ksRuleParam.dataTypeCodes, ksRule.getId(), ksRuleParam.getRule().toJSONString(), auth);

        } catch (Exception e) {
            e.printStackTrace();
        }

//            createFilter(auth,ksRuleParam.id);
        return ResponseEntity.ok().body(ksRule.getId());
    }

    public void createRlRuleField(List<String> dataTypeCodes, Integer ruleId, String ruleExpression, String auth) {
        if (dataTypeCodes == null) {
            return;
        }
        RlRuleField param = new RlRuleField();
        param.setRuleId(ruleId);
        rlRuleFieldService.deleteAll(param);
        List<RlRuleField> rlRuleFieldList = new ArrayList<>();
        List<KsDataField> dataFieldList = queryFactory.selectFrom(qKsDataField).where(qKsDataField.dataTypeCode.in(dataTypeCodes)).fetch();
        dataFieldList.stream().filter(ksDataField ->
                ruleExpression.contains(ksDataField.getCode())
        ).forEach(ksDataField -> {
            RlRuleField rlRuleField = new RlRuleField();
            rlRuleField.setRuleId(ruleId);
            rlRuleField.setDataFieldCode(ksDataField.getCode());
            rlRuleField.setIsMust(true);
            rlRuleField.setDataTypeCode(ksDataField.getDataTypeCode());
            rlRuleFieldList.add(rlRuleField);
        });
        rlRuleFieldService.saveAll(rlRuleFieldList, auth);


    }

    public ResponseEntity<Integer> createFilter(String auth, KsRuleParam ksRuleParam) {
        Integer ruleId = ksRuleParam.getRuleId();
        List<Integer> sourceConfigIds = ksRuleParam.getSysSourceMappingTableIds();
        KsRule rule = ksRuleRepository.getById(ruleId);

        List<SysSourceMappingTable> sourceConfigs = queryFactory.selectFrom(qSysSourceMappingTable).where(qSysSourceMappingTable.id.in(sourceConfigIds)).fetch();
        String tableName = sourceConfigs.get(0).getTableName();
        String dbCode = sourceConfigs.get(0).getDbCode();

        tableName = createView(ksRuleParam, sourceConfigs, dbCode, tableName, auth);

        FilterService.FilterBundle filterBundle = new FilterService.FilterBundle();
        filterBundle.setFilterName(rule.getRuleName());
        filterBundle.setIsTask(false);
        filterBundle.setPower("");
        filterBundle.setResultPower("");
        filterBundle.setAuth(auth);
        List<FilterService.FilterParam> filterParams = new ArrayList<>();
        FilterService.FilterParam filterParam = new FilterService.FilterParam();
        filterParam.setKsRuleId(ruleId);
        filterParam.setTableName(tableName);
        filterParam.setDbCode(dbCode);
        filterParams.add(filterParam);
        filterBundle.setFilterParams(filterParams);

        return ResponseEntity.ok().body(filterService.newFilterTaskReturnId(filterBundle));
    }

    public void createFilters(String auth, KsRuleParam ksRuleParam) {
        List<Integer> ruleIdList = ksRuleParam.getRuleIdList();

        ruleIdList.forEach(ruleId -> {
            ksRuleParam.setRuleId(ruleId);
            List<Integer> sourceMappingTableIds = new ArrayList<>();
            sourceMappingTableIds.add(ksRuleParam.getSysSourceMappingTableId());
            ksRuleParam.setSysSourceMappingTableIds(sourceMappingTableIds);
            createFilter(auth, ksRuleParam);
        });
    }

    public String createView(KsRuleParam ksRuleParam, List<SysSourceMappingTable> sourceConfigs, String dbCode, String tableName, String auth) {

        List<SysSourceMappingTableField> allFields = new ArrayList<>();
        Set<String> selectFields = new HashSet<>();
        Set<String> existFields = new HashSet<>();
        Set<String> existKsDataFieldCodes = new HashSet<>();

        for (int i = 0; i < sourceConfigs.size(); i++) {
            List<SysSourceMappingTableField> fields = queryFactory.selectFrom(qSysSourceMappingTableField).where(qSysSourceMappingTableField.tableName.eq(sourceConfigs.get(i).getTableName()).and(qSysSourceMappingTableField.dbCode.eq(dbCode))).fetch();
            // 多个数据源出现重复field时，取左边数据源的field
            for (SysSourceMappingTableField field : fields) {
                String tableField = field.getTableField();
                if (!existFields.contains(tableField)) {
                    existFields.add(tableField);
                    selectFields.add(sourceConfigs.get(i).getTableName() + "." + tableField + " as " + tableField);
                    allFields.add(field);
                    // 多个数据源出现重复ksDataFieldCode时，取左边数据源的ksDataFieldCode
                    String ksDataFieldCode = field.getKsDataFieldCode();
                    if (ksDataFieldCode != null) {
                        if (existKsDataFieldCodes.contains(ksDataFieldCode)) {
                            field.setKsDataFieldCode(null);
                        } else {
                            existKsDataFieldCodes.add(ksDataFieldCode);
                        }
                    }
                }
            }
        }

        List<String> tableNames = sourceConfigs.stream().map(SysSourceMappingTable::getTableName).collect(Collectors.toList());
        String viewAlias = "RuleId:" + ksRuleParam.getRuleId() + "TableNames:" + String.join(",", tableNames);


        StringBuilder joinOnSQL = new StringBuilder();
        List<String> joinOn = ksRuleParam.joinOn;
        if (joinOn != null && joinOn.size() > 1) {
            for (int i = 1; i < joinOn.size(); i++) {
//                String leftTableName = sourceConfigs.get(i - 1).getTargetTable();
                String rightTableName = sourceConfigs.get(i).getTableName();
                String leftField = joinOn.get(i - 1);
                String rightField = joinOn.get(i);
                joinOnSQL.append(" left join ").append(rightTableName).append(" on ").append(leftField).append("=").append(rightField);
            }
            viewAlias += " JoinOn:" + String.join(",", joinOn);
        }
        Set<String> groupBy = new HashSet<>();
//        List<String> groupBy = ksRuleParam.groupBy;
//        if (groupBy != null && !groupBy.isEmpty()) {
//            groupBySQL.append(" group by ");
//            for (int i = 0; i < groupBy.size(); i++) {
//                if (i > 0) {
//                    groupBySQL.append(",");
//                }
//                if (existFields.contains(groupBy.get(i))) {
//                    groupBySQL.append(groupBy.get(i));
//                }
//            }
//        }

        List<String> countBy = ksRuleParam.countBy;
        if (countBy != null && !countBy.isEmpty()) {
            for (int i = 0; i < countBy.size(); i++) {
                String field = countBy.get(i);
                String fieldTableName = field.substring(0, field.indexOf('.'));
                String fieldName = field.substring(field.indexOf('.') + 1);
                String dataFieldCode = queryFactory.select(qSysSourceMappingTableField.ksDataFieldCode).from(qSysSourceMappingTableField).where(qSysSourceMappingTableField.tableName.eq(fieldTableName).and(qSysSourceMappingTableField.tableField.eq(fieldName).and(qSysSourceMappingTableField.dbCode.eq(dbCode)))).fetchFirst();
                if (StringUtils.isNotBlank(dataFieldCode)) {
                    fieldName = dataFieldCode;
                }
                fieldName = fieldName + "_count";
                selectFields.add("count(" + field + ") as " + fieldName);
                groupBy.add(field);
                SysSourceMappingTableField sysSourceMappingTableField = new SysSourceMappingTableField();
                sysSourceMappingTableField.setTableField(fieldName);
                sysSourceMappingTableField.setTableFieldName("");
                sysSourceMappingTableField.setDbCode(dbCode);
                allFields.add(sysSourceMappingTableField);
            }
            viewAlias += " CountBy:" + String.join(",", countBy);
        }


        String selectSQL = "select " + String.join(",", selectFields);
        String fromSQL = " from " + sourceConfigs.get(0).getTableName();
        String groupBySQL = "";
        if (!groupBy.isEmpty()) {
            groupBySQL = " group by " + String.join(",", groupBy);
        }

        String viewName = "view_" + System.currentTimeMillis();


        SysSourceMappingTable sysSourceMappingTable = queryFactory.selectFrom(qSysSourceMappingTable).where(qSysSourceMappingTable.tableAlias.eq(viewAlias)).fetchFirst();
        if (sysSourceMappingTable == null) {
            String createViewSQL = "create view " + viewName + " as " + selectSQL + fromSQL + joinOnSQL + groupBySQL;
            dbUtil.execute(dbCode, createViewSQL);
            sysSourceMappingTable = new SysSourceMappingTable();
            sysSourceMappingTable.setDbCode(dbCode);
            sysSourceMappingTable.setTableName(viewName);
            sysSourceMappingTable.setTableAlias(viewAlias);
            sysSourceMappingTableService.save(sysSourceMappingTable, auth);

            List<SysSourceMappingTableField> insertFields = new ArrayList<>();
            for (SysSourceMappingTableField field : allFields) {
                SysSourceMappingTableField insertField = new SysSourceMappingTableField();
                BeanUtils.copyProperties(field, insertField);
                insertField.setId(null);
                insertField.setTableName(viewName);
                insertFields.add(insertField);
            }
            sysSourceMappingTableFieldService.saveAll(insertFields, auth);
        } else {
            viewName = sysSourceMappingTable.getTableName();
        }
        return viewName;
    }

    public void createFilter(String auth, Integer ruleId) {
        KsRule rule = ksRuleRepository.getById(ruleId);
        List<RlRuleTable> rlRuleTableList = rlRuleTableRepository.getRlRuleTablesByRuleId(ruleId);
        FilterService.FilterBundle filterBundle = new FilterService.FilterBundle();
        filterBundle.setFilterName(rule.getRuleName());
        filterBundle.setIsTask(false);
        filterBundle.setPower(rule.getPower());
        filterBundle.setAuth(auth);
        List<FilterService.FilterParam> filterParams = new ArrayList<>();
        rlRuleTableList.forEach(rlRuleTable -> {
            FilterService.FilterParam filterParam = new FilterService.FilterParam();
            filterParam.setKsRuleId(rlRuleTable.getRuleId());
            filterParam.setTableName(rlRuleTable.getTableName());

            filterParams.add(filterParam);
        });
        filterBundle.setFilterParams(filterParams);
        filterService.newFilterTask(filterBundle);
    }


    @Transactional
    public ResponseEntity<Object> editKsRule(String auth, KsRuleParam ksRuleParam) {
        KsRule ksRule = queryFactory.selectFrom(qKsRule).where(qKsRule.id.eq(ksRuleParam.id)).fetchOne();
        if (ksRule == null) {
            ksRule = new KsRule();
        }
        ksRule.setRuleName(ksRuleParam.getRuleName());
        ksRule.setRuleExpressionJson(ksRuleParam.getRule().toJSONString());
        ksRule.setRuleType(ksRuleParam.getRuleType());
        ksRule.setShowFields(ksRuleParam.getShowFields());
        ksRule.setDescription(ksRuleParam.getDescription());

        ksRuleService.save(ksRule, auth);

        queryFactory.delete(qRlRuleTable).where(qRlRuleTable.ruleId.eq(ksRule.getId())).execute();

        createRlRuleTable(ksRuleParam.getRlRuleTableList(), ksRule.getId());
        createRlRuleField(ksRuleParam.getDataTypeCodes(), ksRule.getId(), ksRule.getRuleExpressionJson(), auth);
        return ResponseEntity.ok().body("修改成功");
    }


    public ResponseEntity<Object> pageClueByRule(String auth, Map<String, Object> param) {
        IParamBundle bundle = ParamBundle.newBundle(param);
        PageBundle pageBundle = bundle.getPageBundle();
        Integer ruleId = bundle.getInt("ruleId");
        List<ClueAutoResult> clueAutoResultList = queryFactory.selectFrom(qClueAutoResult).where(qClueAutoResult.ruleId.eq(ruleId)).offset(pageBundle.getStart()).limit(pageBundle.getSize()).fetch();
        Long count = queryFactory.select(qClueAutoResult.count()).from(qClueAutoResult).where(qClueAutoResult.ruleId.eq(ruleId)).fetchOne();

        JSONObject page = new JSONObject();
        page.put("list", clueAutoResultList);
        page.put("page", pageBundle.getPage());
        page.put("size", pageBundle.getSize());
        page.put("count", count);
        return ResponseEntity.ok(page);


    }


    public ResponseEntity<Object> getKsRuleListNew(String auth, Map<String, Object> param) {
        BooleanExpression hiddenRuleTypeBooleanExpression = qKsRule.isNull().or(qKsRule.isNotNull());
        IParamBundle bundle = ParamBundle.newBundle(param);
        List<String> hiddenRuleTypes = bundle.get("hiddenRuleTypes", new ArrayList<>());
        if (!hiddenRuleTypes.isEmpty()) {
            for (String hiddenRuleType : hiddenRuleTypes) {
                hiddenRuleTypeBooleanExpression = hiddenRuleTypeBooleanExpression.and(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + hiddenRuleType + ","));
            }
        }
        List<String> ruleTypes = bundle.get("ruleTypes", new ArrayList<>());
        if (ruleTypes.isEmpty()) {
            ruleTypes.add(bundle.getString("ruleType"));
        }
        if (ruleTypes.contains("全部")) {
            ruleTypes = new ArrayList<>();
            ruleTypes.add("全部");
        }
        BooleanExpression ruleTypeExpression = qKsRule.isNull().or(qKsRule.isNotNull());
        for (String ruleType : ruleTypes) {
            ruleTypeExpression = ruleTypeExpression.and(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + ruleType + ","));
        }
        BooleanExpression finalHiddenRuleTypeBooleanExpression = hiddenRuleTypeBooleanExpression;
        PageBundle pageBundle = bundle.getPageBundle();
        String userId = String.valueOf(jwtUtil.getUserId(auth));
        String roleId = String.valueOf(jwtUtil.getRoleId(auth));
        String depId = String.valueOf(jwtUtil.getDepId(auth));
        String name = bundle.getString("name");
        String systemCode = jwtUtil.getSystemCode(auth);
//        String ruleType = bundle.getString("ruleType");
        String[] excludeRuleType = StringUtils.split(bundle.getString("excludeRuleType"), ",");
        String adminArea = bundle.getString("adminArea");
        Long runLastTimeStart = bundle.getLong("runLastTImeStart");
        Long runLastTimeEnd = bundle.getLong("runLastTImeEnd");
        String tableName = bundle.getString("tableName");
        String runLastTimeSort = bundle.getString("runLastTimeSort");
        String adminAreaSort = bundle.getString("adminAreaSort");
        String runCountSort = bundle.getString("runCountSort");
        String ruleNameSort = bundle.getString("ruleNameSort");
        String ruleTypeSort = bundle.getString("ruleTypeSort");
        String dataTypeCode = bundle.getString("dataTypeCode");
        String dataTypeName = bundle.getString("dataTypeName");
        String onlineFlag = bundle.getString("onlineFlag");
        String onlineFlagSort = bundle.getString("onlineFlagSort");

        List<Integer> ruleIdList = bundle.getIntegerList("ruleIdList");

        List<OrderSpecifier<?>> orderFields = new ArrayList<>();

        Map<String, String> params = (Map<String, String>) param.getOrDefault("params", new HashMap<>());
        if (StringUtils.isBlank(runLastTimeSort)) {
            String sort = params.get("runLastTimeSort");
            if (StringUtils.isNotBlank(sort)) {
                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsFilterStatistics.runLastTime.asc());
                } else {
                    orderFields.add(qKsFilterStatistics.runLastTime.desc());
                }
            }
        }
        if (StringUtils.isBlank(runCountSort)) {
            String sort = params.get("runCountSort");
            if (StringUtils.isNotBlank(sort)) {

                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsFilterStatistics.runCount.asc());
                } else {
                    orderFields.add(qKsFilterStatistics.runCount.desc());
                }
            }
        }
        if (StringUtils.isBlank(ruleTypeSort)) {
            String sort = params.get("ruleTypeSort");
            if (StringUtils.isNotBlank(sort)) {

                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsRule.ruleType.asc());
                } else {
                    orderFields.add(qKsRule.ruleType.desc());
                }
            }
        }
        if (StringUtils.isBlank(ruleNameSort)) {
            String sort = params.get("ruleNameSort");
            if (StringUtils.isNotBlank(sort)) {

                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsRule.ruleName.asc());
                } else {
                    orderFields.add(qKsRule.ruleName.desc());
                }
            }
        }
        if (StringUtils.isBlank(onlineFlagSort)) {
            String sort = params.get("onlineFlagSort");
            if (StringUtils.isNotBlank(sort)) {

                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsRule.onlineFlag.asc());
                } else {
                    orderFields.add(qKsRule.onlineFlag.desc());
                }
            }
        }
        orderFields.add(qKsRule.id.desc());


        BooleanExpression booleanExpression = QueryDslUtil.generatePowerExpression(qKsRule, qKsRule.power, userId, roleId, depId).and(finalHiddenRuleTypeBooleanExpression);

        if (StringUtils.isNotBlank(onlineFlag)) {
            booleanExpression = booleanExpression.and(qKsRule.onlineFlag.eq(Boolean.parseBoolean(onlineFlag)));
        }
        if (StringUtils.isNotBlank(dataTypeName)) {
            List<KsRule> ksRuleList = listAvailableRuleContainsDataTypeName(dataTypeName);
            List<Integer> ksRuleIdList = ksRuleList.stream().map(KsRule::getId).collect(Collectors.toList());
            booleanExpression = booleanExpression.and(qKsRule.id.in(ksRuleIdList));
        }
        if (StringUtils.isNotBlank(dataTypeCode)) {
            List<KsRule> ksRuleList = listAvailableRuleContainsDataTypeCode(dataTypeCode);
            List<Integer> ksRuleIdList = ksRuleList.stream().map(KsRule::getId).collect(Collectors.toList());
            booleanExpression = booleanExpression.and(qKsRule.id.in(ksRuleIdList));
        }
        if (!ruleIdList.isEmpty()) {
            booleanExpression = booleanExpression.and(qKsRule.id.in(ruleIdList));
        }
        if (StringUtils.isNotBlank(systemCode)) {
            booleanExpression = booleanExpression.and(qKsRule.systemCode.eq(systemCode).or(qKsRule.systemCode.isNull()));
        }
        if (StringUtils.isNotBlank(name)) {
            booleanExpression = booleanExpression.and(qKsRule.ruleName.contains(name));
        }

        if (excludeRuleType.length > 0) {
            for (String s : excludeRuleType) {
                booleanExpression = booleanExpression.and(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").notLike("%" + "," + s + "," + "%"));
            }
        }
        if (StringUtils.isNotBlank(adminArea)) {
            booleanExpression = booleanExpression.and(qKsRule.adminArea.contains(adminArea));
        }
        if (runLastTimeStart != null && runLastTimeStart > 0) {
            booleanExpression = booleanExpression.and(qKsFilterLog.createTime.gt(LocalDateTime.ofEpochSecond(runLastTimeStart, 0, ZoneOffset.ofHours(8))));
        }
        if (runLastTimeEnd != null && runLastTimeEnd > 0) {
            booleanExpression = booleanExpression.and(qKsFilterLog.createTime.lt(LocalDateTime.ofEpochSecond(runLastTimeEnd, 0, ZoneOffset.ofHours(8))));
        }
        if (StringUtils.isNotBlank(tableName)) {
            booleanExpression = booleanExpression.and(qRlRuleTable.tableName.contains(tableName));
        }
        if (!ruleTypes.isEmpty() && !ruleTypes.contains("全部")) {
            booleanExpression = booleanExpression.and(ruleTypeExpression);
        }
//        if (StringUtils.isNotBlank(runLastTimeSort)) {
//            if (runLastTimeSort.equals("desc")) {
//
//                orderFields.add(qKsFilterLog.createTime.desc());
//            } else {
//                orderFields.add(qKsFilterLog.createTime.asc());
//            }
//        }
//        if (StringUtils.isNotBlank(adminAreaSort)) {
//            if (adminAreaSort.equals("desc")) {
//                orderFields.add(qKsRule.adminArea.desc());
//            } else {
//                orderFields.add(qKsRule.adminArea.asc());
//            }
//        }
//        if (StringUtils.isNotBlank(ruleTypeSort)) {
//            if (ruleTypeSort.equals("desc")) {
//                orderFields.add(qKsRule.ruleType.desc());
//            } else {
//                orderFields.add(qKsRule.ruleType.asc());
//            }
//        }

        Map<String, Integer> groupsCount = new HashMap<>();

        List<String> ruleTypeList = queryFactory.select(qKsRule.ruleType).from(qKsRule).where(booleanExpression).fetch();

        for (String ruleTypeStr : ruleTypeList) {
            if (ruleTypeStr == null) {
                continue;
            }
            String[] ruleTypeArray;
            if (ruleTypeStr.contains(",")) {
                ruleTypeArray = ruleTypeStr.split(",");
            } else {
                ruleTypeArray = new String[]{ruleTypeStr};
            }
            for (String s : ruleTypeArray) {
                if (s.isEmpty() || hiddenRuleTypes.contains(s)) {
                    continue;
                }
                if (groupsCount.containsKey(s)) {
                    groupsCount.put(s, groupsCount.get(s) + 1);
                } else {
                    groupsCount.put(s, 1);
                }
            }
        }


        List<KsRuleEx> ksRules = queryFactory
                .select(qKsRule, qKsFilterStatistics).from(qKsRule)
                .leftJoin(qKsFilterStatistics).on(qKsRule.id.eq(qKsFilterStatistics.ruleId))
//                .leftJoin(qKsFlowLike).on(qKsFlowLike.targetType.eq(TargetType.KS_RULE.getValue()).and(qKsRule.id.eq(qKsFlowLike.targetId)))
//                .leftJoin(qKsFlowComment).on(qKsFlowComment.targetType.eq(TargetType.KS_RULE.getValue()).and(qKsRule.id.eq(qKsFlowComment.targetId)))
                .where(booleanExpression)
                .offset(pageBundle.getStart())
                .limit(pageBundle.getSize())
                .orderBy(orderFields.toArray(new OrderSpecifier[0]))
                .fetch().stream().map(r -> {
                    KsRuleEx ksRuleEx = new KsRuleEx();
                    BeanUtils.copyProperties(r.get(0, KsRule.class), ksRuleEx);
                    KsFilterStatistics ksFilterStatistics = r.get(1, KsFilterStatistics.class);
                    ksRuleEx.setKsFilterStatistics(ksFilterStatistics);
                    return ksRuleEx;
                })
                .peek(e -> {

                    Set<String> ruleFields = new HashSet<>();
                    e.setRuleExpressionJsonStr(String.valueOf(e.getRuleExpressionJson()));
                    if (e.getRuleExpressionJsonStr() != null) {
                        Pattern pattern = Pattern.compile("\"field\":\\s*\"(\\w+)\"");
                        Matcher matcher = pattern.matcher(e.getRuleExpressionJsonStr());
                        while (matcher.find()) {
                            ruleFields.add(matcher.group(1));
                        }
                    }
                    e.setRuleFields(new ArrayList<>(ruleFields));
                    if (StringUtils.isBlank(e.getShowFields())) {
                        e.setShowFields(StringUtils.join(e.getRuleFields(), ","));
                    }
                    if (pageBundle.getSize() >= 999) {
                        return;
                    }
                    List<String> dataTypeCodes = queryFactory.selectDistinct(qRlRuleField.dataTypeCode).from(qRlRuleField).where(qRlRuleField.ruleId.eq(e.getId())).fetch();
                    e.setDataTypeCodes(dataTypeCodes);
                    KsFilterLog ksFilterLog = ksFilterLogRepository.getFirstByRuleId(e.getId());
                    if (ksFilterLog != null) {
                        e.setCreateTime(ksFilterLog.getCreateTime());
                        e.setMatch(ksFilterLog.getKsMatch());
                    }
                    log.info("" + e.getId());

                    KsFlowLike ksFlowLikeParam = new KsFlowLike();
                    ksFlowLikeParam.setStatus(1);
                    ksFlowLikeParam.setTargetType(TargetType.KS_RULE.getValue());
                    ksFlowLikeParam.setTargetId(e.getId());
                    List<KsFlowLike> ksFlowLikeList = ksFlowLikeService.findAllByEntity(ksFlowLikeParam);
                    e.setKsFlowLikeList(ksFlowLikeList);
                    e.setKsFlowLikeCount(ksFlowLikeList.size());

                    KsFlowComment ksFlowCommentParam = new KsFlowComment();
                    ksFlowCommentParam.setTargetType(TargetType.KS_RULE.getValue());
                    ksFlowCommentParam.setTargetId(e.getId());
                    List<KsFlowComment> ksFlowCommentList = ksFlowCommentService.findAllByEntity(ksFlowCommentParam);
                    e.setKsFlowCommentList(ksFlowCommentList);
                    e.setKsFlowCommentCount(ksFlowCommentList.size());

                    e.setRuleExpressionJson(null);
                })
                .collect(Collectors.toList());

        Integer count = queryFactory.select(qKsRule.count()).from(qKsRule)
                .where(booleanExpression)
                .groupBy(qKsRule.id)
                .fetch().size();

        JSONObject page = new JSONObject();
        page.put("list", ksRules);
        page.put("page", pageBundle.getPage());
        page.put("size", pageBundle.getSize());
        page.put("count", count);
        page.put("groupsCount", groupsCount);

        return ResponseEntity.ok(Collections.singletonList(page));
    }

    public ResponseEntity<Object> getKsRuleList(String auth, Map<String, Object> param) {
        BooleanExpression hiddenRuleTypeBooleanExpression = qKsRule.isNull().or(qKsRule.isNotNull());
        IParamBundle bundle = ParamBundle.newBundle(param);
        List<String> hiddenRuleTypes = bundle.get("hiddenRuleTypes", new ArrayList<>());
        if (!hiddenRuleTypes.isEmpty()) {
            for (String hiddenRuleType : hiddenRuleTypes) {
                hiddenRuleTypeBooleanExpression = hiddenRuleTypeBooleanExpression.and(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + hiddenRuleType + ","));
            }
        }
        List<String> ruleTypes = bundle.get("ruleTypes", new ArrayList<>());
        if (ruleTypes.isEmpty()) {
            ruleTypes.add(bundle.getString("ruleType"));
        }
        if (ruleTypes.contains("全部") || StringUtils.isBlank(bundle.getString("ruleType"))) {
            ruleTypes = new ArrayList<>();
            ruleTypes.add("全部");
        }
        BooleanExpression finalHiddenRuleTypeBooleanExpression = hiddenRuleTypeBooleanExpression;
        return ResponseEntity.ok(ruleTypes.stream().map(ruleType -> {
            PageBundle pageBundle = bundle.getPageBundle();
            String userId = String.valueOf(jwtUtil.getUserId(auth));
            String roleId = String.valueOf(jwtUtil.getRoleId(auth));
            String depId = String.valueOf(jwtUtil.getDepId(auth));
            String name = bundle.getString("name");
            String systemCode = jwtUtil.getSystemCode(auth);
//        String ruleType = bundle.getString("ruleType");
            String[] excludeRuleType = StringUtils.split(bundle.getString("excludeRuleType"), ",");
            String adminArea = bundle.getString("adminArea");
            Long runLastTimeStart = bundle.getLong("runLastTImeStart");
            Long runLastTimeEnd = bundle.getLong("runLastTImeEnd");
            String tableName = bundle.getString("tableName");
            String runLastTimeSort = bundle.getString("runLastTimeSort");
            String adminAreaSort = bundle.getString("adminAreaSort");
            String ruleTypeSort = bundle.getString("ruleTypeSort");
            String ruleNameSort = bundle.getString("ruleNameSort");
            String runCountSort = bundle.getString("runCountSort");
            String dataTypeCode = bundle.getString("dataTypeCode");
            String dataTypeName = bundle.getString("dataTypeName");
            String onlineFlag = bundle.getString("onlineFlag");

            List<OrderSpecifier<?>> orderFields = new ArrayList<>();
            orderFields.add(qKsRule.id.desc());

            Map<String, String> params = (Map<String, String>) param.getOrDefault("params", new HashMap<>());
            if (StringUtils.isBlank(runLastTimeSort)) {
                String sort = params.get("runLastTimeSort");
                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsFilterStatistics.runLastTime.asc());
                } else {
                    orderFields.add(qKsFilterStatistics.runLastTime.desc());
                }
            }
            if (StringUtils.isBlank(runCountSort)) {
                String sort = params.get("runCountSort");
                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsFilterStatistics.runCount.asc());
                } else {
                    orderFields.add(qKsFilterStatistics.runCount.desc());
                }
            }
            if (StringUtils.isBlank(ruleTypeSort)) {
                String sort = params.get("ruleTypeSort");
                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsRule.ruleType.asc());
                } else {
                    orderFields.add(qKsRule.ruleType.desc());
                }
            }
            if (StringUtils.isBlank(ruleNameSort)) {
                String sort = params.get("ruleNameSort");
                if ("asc".equalsIgnoreCase(sort)) {
                    orderFields.add(qKsRule.ruleName.asc());
                } else {
                    orderFields.add(qKsRule.ruleName.desc());
                }
            }


            List<Integer> ruleIdList = bundle.getIntegerList("ruleIdList");

            BooleanExpression booleanExpression = QueryDslUtil.generatePowerExpression(qKsRule, qKsRule.power, userId, roleId, depId).and(finalHiddenRuleTypeBooleanExpression);

            if (StringUtils.isNotBlank(onlineFlag)) {
                booleanExpression = booleanExpression.and(qKsRule.onlineFlag.eq(Boolean.parseBoolean(onlineFlag)));
            }
            if (StringUtils.isNotBlank(dataTypeName)) {
                List<KsRule> ksRuleList = listAvailableRuleContainsDataTypeName(dataTypeName);
                List<Integer> ksRuleIdList = ksRuleList.stream().map(KsRule::getId).collect(Collectors.toList());
                booleanExpression = booleanExpression.and(qKsRule.id.in(ksRuleIdList));
            }
            if (StringUtils.isNotBlank(dataTypeCode)) {
                List<KsRule> ksRuleList = listAvailableRuleContainsDataTypeCode(dataTypeCode);
                List<Integer> ksRuleIdList = ksRuleList.stream().map(KsRule::getId).collect(Collectors.toList());
                booleanExpression = booleanExpression.and(qKsRule.id.in(ksRuleIdList));
            }
            if (!ruleIdList.isEmpty()) {
                booleanExpression = booleanExpression.and(qKsRule.id.in(ruleIdList));
            }
            if (StringUtils.isNotBlank(systemCode)) {
                booleanExpression = booleanExpression.and(qKsRule.systemCode.eq(systemCode).or(qKsRule.systemCode.isNull()));
            }
            if (StringUtils.isNotBlank(name)) {
                booleanExpression = booleanExpression.and(qKsRule.ruleName.contains(name));
            }
            if (StringUtils.isNotBlank(ruleType)) {
                if (!ruleType.equals("全部")) {
                    booleanExpression = booleanExpression.and(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + ruleType + ","));
                }
            }

            if (excludeRuleType.length > 0) {
                BooleanBuilder booleanBuilder = new BooleanBuilder();
                for (String s : excludeRuleType) {
                    booleanBuilder.and(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").notLike("%" + "," + s + "," + "%"));
                }
                booleanExpression = booleanExpression.and(qKsRule.ruleType.isNull().or(booleanBuilder));
            }
            if (StringUtils.isNotBlank(adminArea)) {
                booleanExpression = booleanExpression.and(qKsRule.adminArea.contains(adminArea));
            }
            if (runLastTimeStart != null && runLastTimeStart > 0) {
                booleanExpression = booleanExpression.and(qKsFilterLog.createTime.gt(LocalDateTime.ofEpochSecond(runLastTimeStart, 0, ZoneOffset.ofHours(8))));
            }
            if (runLastTimeEnd != null && runLastTimeEnd > 0) {
                booleanExpression = booleanExpression.and(qKsFilterLog.createTime.lt(LocalDateTime.ofEpochSecond(runLastTimeEnd, 0, ZoneOffset.ofHours(8))));
            }
            if (StringUtils.isNotBlank(tableName)) {
                booleanExpression = booleanExpression.and(qRlRuleTable.tableName.contains(tableName));
            }


            if (StringUtils.isNotBlank(runLastTimeSort)) {
                if (runLastTimeSort.equals("desc")) {
                    orderFields.add(qKsFilterLog.createTime.desc());
                } else {
                    orderFields.add(qKsFilterLog.createTime.asc());
                }
            }
            if (StringUtils.isNotBlank(adminAreaSort)) {
                if (adminAreaSort.equals("desc")) {
                    orderFields.add(qKsRule.adminArea.desc());
                } else {
                    orderFields.add(qKsRule.adminArea.asc());
                }
            }
            if (StringUtils.isNotBlank(ruleTypeSort)) {
                if (ruleTypeSort.equals("desc")) {
                    orderFields.add(qKsRule.ruleType.desc());
                } else {
                    orderFields.add(qKsRule.ruleType.asc());
                }
            }

            Map<String, Integer> groupsCount = new HashMap<>();

            List<String> ruleTypeList = queryFactory.select(qKsRule.ruleType).from(qKsRule).where(booleanExpression).fetch();

            for (String ruleTypeStr : ruleTypeList) {
                if (ruleTypeStr == null) {
                    continue;
                }
                String[] ruleTypeArray;
                if (ruleTypeStr.contains(",")) {
                    ruleTypeArray = ruleTypeStr.split(",");
                } else {
                    ruleTypeArray = new String[]{ruleTypeStr};
                }
                for (String s : ruleTypeArray) {
                    if (s.isEmpty() || hiddenRuleTypes.contains(s)) {
                        continue;
                    }
                    if (groupsCount.containsKey(s)) {
                        groupsCount.put(s, groupsCount.get(s) + 1);
                    } else {
                        groupsCount.put(s, 1);
                    }
                }
            }


            List<KsRuleEx> ksRules = queryFactory
                    .select(qKsRule, qKsFilterStatistics).from(qKsRule)
                    .leftJoin(qKsFilterStatistics).on(qKsRule.id.eq(qKsFilterStatistics.ruleId))
                    .where(booleanExpression)
                    .offset(pageBundle.getStart())
                    .limit(pageBundle.getSize())
                    .orderBy(orderFields.toArray(new OrderSpecifier[0]))
                    .fetch().stream().map(r -> {
                        KsRuleEx ksRuleEx = new KsRuleEx();
                        BeanUtils.copyProperties(r.get(0, KsRule.class), ksRuleEx);
                        KsFilterStatistics ksFilterStatistics = r.get(1, KsFilterStatistics.class);
                        ksRuleEx.setKsFilterStatistics(ksFilterStatistics);
                        return ksRuleEx;
                    })
                    .peek(e -> {
                        if (pageBundle.getSize() == 9999) {
                            return;
                        }
                        Set<String> ruleFields = new HashSet<>();
                        e.setRuleExpressionJsonStr(String.valueOf(e.getRuleExpressionJson()));
                        if (e.getRuleExpressionJsonStr() != null) {
                            Pattern pattern = Pattern.compile("\"field\":\\s*\"(\\w+)\"");
                            Matcher matcher = pattern.matcher(e.getRuleExpressionJsonStr());
                            while (matcher.find()) {
                                ruleFields.add(matcher.group(1));
                            }
                        }
                        log.info("ruleId:" + e.getId());
                        List<String> dataTypeCodes = queryFactory.selectDistinct(qRlRuleField.dataTypeCode).from(qRlRuleField).where(qRlRuleField.ruleId.eq(e.getId())).fetch();
                        e.setDataTypeCodes(dataTypeCodes);
                        List<RlRuleTable> rlRuleTables = rlRuleTableRepository.getRlRuleTablesByRuleId(e.getId());
                        List<String> tableNames = rlRuleTables.stream().map(RlRuleTable::getTableName).collect(Collectors.toList());
                        List<String> tableColumnContents = rlRuleTables.stream().map(r -> r.getTableName() + "." + r.getColumnName() + "." + r.getMatchContent()).collect(Collectors.toList());
                        List<String> tableColumnNoMatchContents = rlRuleTables.stream().map(r -> r.getTableName() + "." + r.getColumnName() + "." + r.getNoMatchContent()).collect(Collectors.toList());
                        KsFilterLog ksFilterLog = ksFilterLogRepository.getFirstByRuleId(e.getId());
                        if (ksFilterLog != null) {
                            e.setCreateTime(ksFilterLog.getCreateTime());
                            e.setMatch(ksFilterLog.getKsMatch());
                        }
                        log.info("" + e.getId());
                        e.setRuleFields(new ArrayList<>(ruleFields));
                        e.setRlRuleTables(rlRuleTables);
                        e.setTableColumnContents(tableColumnContents);
                        e.setTableColumnNoMatchContents(tableColumnNoMatchContents);
                        e.setTableNames(tableNames);
                        e.setRuleExpressionJson(null);
                    })
                    .collect(Collectors.toList());

            Integer count = queryFactory.select(qKsRule.count()).from(qKsRule)
                    .where(booleanExpression)
                    .groupBy(qKsRule.id)
                    .fetch().size();

            JSONObject page = new JSONObject();
            page.put("list", ksRules);
            page.put("page", pageBundle.getPage());
            page.put("size", pageBundle.getSize());
            page.put("count", count);
            page.put("groupsCount", groupsCount);
            return page;
        }).collect(Collectors.toList()));

    }


    @Transactional
    public ResponseEntity<Object> delKsRule(String auth, Integer id) {
//        JSONObject user = getUserFromRedis(auth);
        long q1 = queryFactory.delete(qKsRule).where(qKsRule.id.eq(id)).execute();
        long q2 = queryFactory.delete(qRlRuleTable).where(qRlRuleTable.ruleId.eq(id)).execute();
        return ResponseEntity.ok().body("删除成功");
    }

    public ResponseEntity<Object> getClassFiledData(String tableName, String fieldName, String dbCode) {
        List<String> classFiledData = queryFactory.select(qKsClassField.value).from(qKsClassField).where(qKsClassField.tableName.eq(tableName).and(qKsClassField.filedName.eq(fieldName))).fetch();

        if (classFiledData.isEmpty()) {
            List<Map<String, Object>> records = fetchSql(dbCode,
                    "SELECT " + fieldName + " FROM " + tableName + " GROUP BY " + fieldName);
            classFiledData = records.stream().map(r -> r.get(fieldName))
                    .filter(r -> StringUtils.isNotBlank(String.valueOf(r))).filter(Objects::nonNull)
                    .map(Object::toString)
                    .collect(Collectors.toList());

            updateClassField(tableName, fieldName, true, dbCode);
        }
        return ResponseEntity.ok().body(classFiledData);
    }


    public void initClassField() {

//        List<KsTableField> ksTableFields = queryFactory.selectFrom(qKsTableField).where(qKsTableField.tableFieldType.eq("class")).fetch();
//        for (KsTableField ksTableField : ksTableFields) {
//            String tableName = ksTableField.getTableName();
//            String fieldName = ksTableField.getTableField();
//            updateClassField(tableName, fieldName, false, null);
//        }
    }

    @Transactional
    public void updateClassField(String tableName, String fieldName, boolean update, String dbCode) {
        try {
            BooleanExpression booleanExpression = qKsClassField.tableName.eq(tableName).and(qKsClassField.filedName.eq(fieldName));

            if (update) {
                queryFactory.delete(qKsClassField).where(booleanExpression).execute();
            }

            Long count = queryFactory.select(qKsClassField.count()).from(qKsClassField).where(booleanExpression).fetchOne();
            if (count != null && count == 0) {
                List<Map<String, Object>> records = dbUtil.query(dbCode,
                        "SELECT " + fieldName + " FROM " + tableName + " GROUP BY "
                                + fieldName);
                List<String> values = records.stream().map(r -> r.get(fieldName))
                        .filter(r -> StringUtils.isNotBlank(String.valueOf(r))).filter(Objects::nonNull)
                        .map(Object::toString)
                        .collect(Collectors.toList());
                List<KsClassField> ksClassFields = new ArrayList<>();
                for (String value : values) {
                    KsClassField ksClassField = new KsClassField();
                    ksClassField.setTableName(tableName);
                    ksClassField.setFiledName(fieldName);
                    ksClassField.setValue(value);
                    ksClassFields.add(ksClassField);
                    if (ksClassFields.size() >= 50) {
                        ksClassFieldRepository.saveAll(ksClassFields);
                        ksClassFields.clear();
                    }
                }
                if (!ksClassFields.isEmpty()) {
                    ksClassFieldRepository.saveAll(ksClassFields);
                }
                log.info("Cache " + tableName + " " + fieldName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public ResponseEntity<Object> rlRuleKsTables(Integer id) {
        List<String> tableNameList = queryFactory.select(qRlRuleTable.tableName).from(qRlRuleTable).where(qRlRuleTable.ruleId.eq(id)).fetch();
        List<SysSourceConfig> sysSourceConfigList = queryFactory.selectFrom(qSysSourceConfig).where(qSysSourceConfig.targetTable.in(tableNameList)).fetch();
        return ResponseEntity.ok().body(sysSourceConfigList);
    }


    public ResponseEntity<Object> updateClassFiledData(String tableName, String fieldName, String dbCode) {
        updateClassField(tableName, fieldName, true, dbCode);
        return ResponseEntity.ok().body("更新成功");
    }


    public ResponseEntity<Object> getFunc() {
        List<JSONObject> funcList = new ArrayList<>();
        for (Map.Entry<String, IFunc> entry : ruleMatcher.getFuncMap().entrySet()) {
            JSONObject item = new JSONObject();
            item.put("name", entry.getValue().funcName());
            item.put("func", entry.getKey());
            funcList.add(item);
        }
        return ResponseEntity.ok().body(funcList);
    }

    public ResponseEntity<Object> listRuleType() {
        List<String> ruleTypeList = queryFactory.select(qKsRule.ruleType).from(qKsRule).fetch();
        String all = String.join(",", ruleTypeList);
        String[] allArray = all.split(",");
        List<String> res = Arrays.stream(allArray).filter(r -> r != null && !r.isEmpty()).collect(collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o))), ArrayList::new));
        return ResponseEntity.ok(res);
    }


    public ResponseEntity<Object> listRuleType(List<String> hiddenContainsList) {
        Set<String> res = new HashSet<>();
        List<String> ruleTypeList = queryFactory.select(qKsRule.ruleType).from(qKsRule).fetch();
        ruleTypeList.stream().filter(r -> r != null && !r.isEmpty()).forEach(r -> {
            if (r.contains(",")) {
                String[] item = r.split(",");
                Arrays.stream(item).filter(hiddenContainsList::contains).findAny().ifPresent(i -> {
                    res.addAll(Arrays.asList(item));
                    res.remove(i);
                });
            }
        });
        return ResponseEntity.ok(res);
    }


    public ResponseEntity<Object> listClueResultByRuleId(Integer ruleId) {
        List<ClueAutoResult> res = queryFactory.selectFrom(qClueAutoResult).where(qClueAutoResult.ruleId.eq(ruleId)).fetch();
        return ResponseEntity.ok(res);
    }


    @Transactional
    public ResponseEntity updateRuleAvailable(Integer ruleId, Integer available) {
        long res = queryFactory.update(qKsRule).set(qKsRule.isAvailable, available).where(qKsRule.id.eq(ruleId)).execute();
        return ResponseEntity.ok(res);
    }

    public ResponseEntity<Object> testFilterData(FilterDataParam filterDataParam) {
        List<KsRule> ruleList = new ArrayList<>();
        if (filterDataParam.ruleIdList != null && !filterDataParam.ruleIdList.isEmpty()) {
            List<KsRule> ksRuleList = queryFactory.selectFrom(qKsRule).where(qKsRule.id.in(filterDataParam.ruleIdList)).fetch();
            ruleList.addAll(ksRuleList);
        }
        if (filterDataParam.ruleId != null) {
            KsRule rule = queryFactory.selectFrom(qKsRule).where(qKsRule.id.eq(filterDataParam.ruleId)).fetchOne();
            if (rule != null) {
                ruleList.add(rule);
            }
        }

        List<String> needFields = new ArrayList<>();
        AtomicBoolean match = new AtomicBoolean(true);
        ruleList.forEach(r -> {
            List<String> ksRuleFields = getKsRuleFields(r.getRuleExpressionJson());
            Set<String> keySet = filterDataParam.data.keySet();
            ksRuleFields.forEach(ksRuleField -> {
                if (!keySet.contains(ksRuleField)) {
                    if (!needFields.contains(ksRuleField)) {
                        needFields.add(ksRuleField);
                    }
                    match.set(false);
                }
            });
        });
        JSONObject res = new JSONObject();

        if (!needFields.isEmpty()) {
            res.put("msg", "缺少字段" + String.join(",", needFields));
        }
        res.put("match", match.get());
        return ResponseEntity.ok(res);
    }

    public ResponseEntity<Object> filterData(FilterDataParam filterDataParam) {
        List<KsRule> ruleList = new ArrayList<>();
        if (filterDataParam.ruleIdList != null && !filterDataParam.ruleIdList.isEmpty()) {
            List<KsRule> ksRuleList = queryFactory.selectFrom(qKsRule).where(qKsRule.id.in(filterDataParam.ruleIdList)).fetch();
            ruleList.addAll(ksRuleList);
        }
        if (filterDataParam.ruleId != null) {
            KsRule rule = queryFactory.selectFrom(qKsRule).where(qKsRule.id.eq(filterDataParam.ruleId)).fetchOne();
            if (rule != null) {
                ruleList.add(rule);
            }
        }

        if (filterDataParam.tableName != null) {
            List<Integer> ruleIdList = queryFactory.select(qRlRuleTable.ruleId).from(qRlRuleTable).where(qRlRuleTable.tableName.eq(filterDataParam.tableName)).fetch();
            List<KsRule> ksRuleList = queryFactory.selectFrom(qKsRule).where(qKsRule.id.in(ruleIdList)).fetch();
            ruleList.addAll(ksRuleList);
        }

        List<String> totalErrorList = new ArrayList<>();
        List<String> totalTipsList = new ArrayList<>();
        List<JSONObject> cpJsonList = new ArrayList<>();
        List<String> descList = new ArrayList<>();
        List<String> ruleNameList = new ArrayList<>();
        AtomicBoolean match = new AtomicBoolean(true);
        ruleList.forEach(r -> {
            if (!r.getRuleExpressionJson().contains("{#")) {
                List<String> errorList = new ArrayList<>();
                List<String> tipsList = new ArrayList<>();
                JSONObject cpJson = new JSONObject();
                boolean thisMatch = RuleMatcher.execMatchRule(new JSONObject(filterDataParam.data), JSONObject.parseObject(r.getRuleExpressionJson()), cpJson, errorList, tipsList);
                if (!thisMatch) {
                    match.set(false);
                }
                totalErrorList.addAll(errorList);
                totalTipsList.addAll(tipsList);
                cpJsonList.add(cpJson);
                descList.add(r.getDescription());
                ruleNameList.add(r.getRuleName() + ":" + thisMatch);
            }

        });

        JSONObject res = new JSONObject();
        res.put("match", match.get());
        res.put("error", totalErrorList);
        res.put("tips", totalTipsList);
        res.put("cpJson", cpJsonList);
        res.put("description", descList);
        res.put("ruleNameList", ruleNameList);
        return ResponseEntity.ok(res);
    }

    public boolean filterData(Integer ruleId, Map<String, Object> data) {
//        log.info("------------------------filterData-tableName: {}", filterDataParam.tableName);
        List<KsRule> ruleList = new ArrayList<>();
        KsRule rule = queryFactory.selectFrom(qKsRule).where(qKsRule.id.eq(ruleId)).fetchOne();
        if (rule != null) {
            ruleList.add(rule);
        }
        for (KsRule ksRule : ruleList) {
            if (!ksRule.getRuleExpressionJson().contains("{#")) {
                List<String> errorList = new ArrayList<>();
                List<String> tipsList = new ArrayList<>();
                JSONObject cpJson = new JSONObject();
                boolean thisMatch = RuleMatcher.execMatchRule(new JSONObject(data), JSONObject.parseObject(ksRule.getRuleExpressionJson()), cpJson, errorList, tipsList);
                if (!thisMatch) {
                    return false;
                }
            }
        }
        return true;
    }

    public List<Map<String, Object>> filterDataList(Integer ruleId, List<Map<String, Object>> data) {
        return data.stream().filter(item -> filterData(ruleId, item)).collect(Collectors.toList());
    }

    @Transactional
    public void createRlRuleTable(List<RlRuleTable> rlRuleTableList, Integer ruleId) {
        if (rlRuleTableList == null || rlRuleTableList.isEmpty()) {
            return;
        }
        Integer id = queryFactory.select(qRlRuleTable.id.max()).from(qRlRuleTable).fetchFirst();
        for (RlRuleTable rlRuleTable : rlRuleTableList) {
            rlRuleTable.setId(++id);
            rlRuleTable.setRuleId(ruleId);
            rlRuleTableRepository.save(rlRuleTable);
        }
    }


    public List<Map<String, Object>> fetchSql(String dbCode, String sql) {
        return dbUtil.query(dbCode, sql);
    }


    @Data
    public static class FilterDataParam {
        private String tableName;
        private Integer ruleId;

        private List<Integer> ruleIdList;
        private Map<String, Object> data;
    }

    @Data
    public static class KsRuleParam {
        private String description;
        private String showFields;
        List<Integer> ruleIdList;
        private List<String> countBy;

        private List<String> groupBy;
        private List<String> joinOn;
        Integer ruleId;
        List<Integer> sysSourceMappingTableIds;
        Integer sysSourceMappingTableId;
        private List<String> dataTypeCodes;
        private String userId;

        private String roleId;

        private JSONObject rule;

        private String ruleName;

        private Integer id;

        private List<String> tableNames = new ArrayList<>();

        private String ruleType;

        private List<RlRuleTable> rlRuleTableList = new ArrayList<>();
//        private  List<String> tableColumnContents = new ArrayList<>();
//        private List<String> tableColumnNoMatchContents = new ArrayList<>();

        private String power;
        private String resultPower;

        private boolean isForward;
    }

    @EqualsAndHashCode(callSuper = false)
    @Data
    public static class KsRuleEx extends KsRule {

        private List<KsFlowComment> ksFlowCommentList;
        private List<KsFlowLike> ksFlowLikeList;
        private Integer ksFlowLikeCount;
        private Integer ksFlowCommentCount;
        private String ruleExpressionJsonStr;
        private List<String> tableNames;
        private List<String> tableColumnContents;
        private List<String> tableColumnNoMatchContents;
        private Integer match;
        private LocalDateTime createTime;
        private KsFilterStatistics ksFilterStatistics;
        private List<String> ruleFields;
        private List<RlRuleTable> rlRuleTables;
        private List<String> dataTypeCodes;
    }

}
